<?php


namespace core\utils;


use Closure;
use core\exception\BadException;
use yzh52521\WebmanLock\Locker;

class LockUtil
{
    /**
     * @param $key
     * @param Closure $callback
     * @return string
     * @throws BadException
     */
    static function tryLock($key, Closure $callback)
    {
        $lock = Locker::lock($key);
        if (!$lock->acquire()) {
            throw new BadException('操作太频繁，请稍后再试');
        }
        try {
            // 执行实际业务
            return $callback();
        } finally {
            $lock->release();
        }
    }

    /**
     * @param $key
     * @param Closure $callback
     * @return string
     */
    static function lock($key, Closure $callback)
    {
        $lock = Locker::lock($key);
        if ($lock->acquire()) {
            //成功拿到了锁
            try {
                // 执行实际业务
                $callback();
                return true;
            } finally {
                $lock->release();
            }
        }
        return false;
    }


    /**
     * 尝试获取锁并执行闭包，带重试机制
     * 因为使用了usleep函数 最好别用 还没想好如何实现在webman中不使用usleep实现重试机制
     * @param string $key
     * @param Closure $callback 获取锁后执行的闭包
     * @param int $retryTimes 重试次数
     * @param int $waitMilliseconds 重试等待时间（毫秒）
     * @return mixed
     */
    static function lockWithRetry(string $key, Closure $callback, int $retryTimes = 3, int $waitMilliseconds = 100)
    {
        for ($i = 0; $i < $retryTimes; $i++) {
            $lock = Locker::lock($key);
            if ($lock->acquire(true)) {
                //成功拿到了锁
                try {
                    // 执行实际业务
                    $callback();
                    return true;
                } finally {
                    $lock->release();
                }
            }
            // 没拿到等待重试 等待一段时间后重试
            usleep($waitMilliseconds * 1000);
        }
        return false;
    }

}